package com.efun.center.http.handler;

import com.efun.center.datasource.BindingDataSourceKey;
import com.efun.center.http.config.ParamInfo;
import com.efun.center.http.config.DataType;
import com.efun.center.http.config.MethodMapper;
import com.efun.center.http.service.SendMailService;
import com.efun.center.http.util.JsonUtils;
import org.apache.http.HttpResponse;
import org.apache.http.NameValuePair;
import org.apache.http.client.config.RequestConfig;
import org.apache.http.client.entity.UrlEncodedFormEntity;
import org.apache.http.client.methods.HttpPost;
import org.apache.http.entity.StringEntity;
import org.apache.http.impl.client.CloseableHttpClient;
import org.apache.http.impl.client.HttpClients;
import org.apache.http.impl.conn.SystemDefaultRoutePlanner;
import org.apache.http.message.BasicNameValuePair;
import org.apache.http.util.EntityUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import java.beans.BeanInfo;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.io.IOException;
import java.lang.reflect.Method;
import java.net.ProxySelector;
import java.sql.Timestamp;
import java.text.SimpleDateFormat;
import java.util.*;

@Component
public class HttpPostHandler implements HttpSupport {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private SendMailService sendMailService;

    public static final String ENTITY = "_ENTITY";

    public static final String UTF8 = "utf-8";

    @Override
    public String deal(ParamInfo paramInfo) {
        MethodMapper mapper = paramInfo.getMethodMapper();
        String area = BindingDataSourceKey.getDataSourceToken();
        String areaUrl = mapper.getAreaUrl().get(area);
        if (StringUtils.isEmpty(areaUrl)) {
            return null;
        }

        String fullUrl = "";
        String result = "";
        String body = "";
        int timeout = paramInfo.getTimeout();
        RequestConfig requestConfig = RequestConfig.custom().setSocketTimeout(timeout).setConnectTimeout(timeout)
                .setConnectionRequestTimeout(timeout).build();
        SystemDefaultRoutePlanner routePlanner = new SystemDefaultRoutePlanner(ProxySelector.getDefault());
        CloseableHttpClient httpClient = HttpClients.custom().setRoutePlanner(routePlanner).setDefaultRequestConfig(requestConfig).build();
        try {
            fullUrl = areaUrl + "/" + mapper.getUrl();
            logger.info(fullUrl);
            HttpPost httpPost = new HttpPost(fullUrl);
            Map<String, Object> postParams = transferParams(paramInfo.getParams());
            if (paramInfo.getContentType().equalsIgnoreCase(DataType.JSON.toString())) {
                body = JsonUtils.toString(postParams);
                StringEntity entity = new StringEntity(body, UTF8);
                entity.setContentType(DataType.JSON.toString());
                httpPost.setEntity(entity);
            } else { // DataType.FORM
                List<NameValuePair> pairs = new ArrayList<NameValuePair>();
                for (Map.Entry<String, Object> entry : postParams.entrySet()) {
                    pairs.add(new BasicNameValuePair(entry.getKey(), entry.getValue().toString()));
                }
                body = pairs.toString();
                UrlEncodedFormEntity entity = new UrlEncodedFormEntity(pairs, UTF8);
                httpPost.setEntity(entity);
            }

            HttpResponse response = httpClient.execute(httpPost);
            result = EntityUtils.toString(response.getEntity());
            logger.info(result);
            return result;
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                if (httpClient != null) {
                    httpClient.close();
                }
            } catch (IOException e) {
                e.printStackTrace();
            }
            sendMailService.sendErrorEmail(paramInfo, area, fullUrl, result, body);
        }
        return null;
    }

    private Map<String, Object> transferParams(Map<String, Object> params) {
        Map<String, Object> returnParams = new HashMap<String, Object>();
        for (Map.Entry<String, Object> entry : params.entrySet()) {
            if (entry.getKey().equalsIgnoreCase(ENTITY)) {
                try {
                    Object obj = entry.getValue();
                    BeanInfo beanInfo = Introspector.getBeanInfo(obj.getClass());
                    PropertyDescriptor[] propertyDescriptors = beanInfo.getPropertyDescriptors();
                    for (PropertyDescriptor property : propertyDescriptors) {
                        String key = property.getName();
                        if (!key.equals("class")) {
                            Method getter = property.getReadMethod();
                            Object value = getter.invoke(obj);
                            if (value instanceof Date) {
                                Date d = (Date) value;
                                value = dateToStr(d);
                            }
                            if (value instanceof Timestamp) {
                                Timestamp d = (Timestamp) value;
                                value = dateToStr(new Date(d.getTime()));
                            }
                            returnParams.put(key, value);
                        }
                    }
                } catch (Exception e) {
                    e.printStackTrace();
                }
            } else {
                returnParams.put(entry.getKey(), entry.getValue());
            }
        }
        return returnParams;
    }

    private String dateToStr(Date d) {
        return new SimpleDateFormat("yyyy-MM-dd HH:mm:ss").format(d);
    }

}
